package cn.tsvtc.shop.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.tsvtc.shop.constant.RedisConstant;
import cn.tsvtc.shop.entity.CartItem;
import cn.tsvtc.shop.entity.CartItemVO;
import cn.tsvtc.shop.entity.LoginUser;
import cn.tsvtc.shop.entity.ResultMessage;
import cn.tsvtc.shop.mapper.ProductMapper;
import cn.tsvtc.shop.pojo.Product;
import cn.tsvtc.shop.service.CartService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.Cookie;
import java.util.*;

/**
 * @author: Athena
 * @date: 2020/11/3 20:40
 * @description:
 */
@Service
@Slf4j
public class CartServiceImpl implements CartService {

    private RestTemplate restTemplate;

    private ProductMapper productMapper;

    private RedisTemplate redisTemplate;

    @Autowired
    public CartServiceImpl(RedisTemplate redisTemplate,ProductMapper productMapper,RestTemplate restTemplate){
        this.redisTemplate=redisTemplate;
        this.productMapper=productMapper;
        this.restTemplate=restTemplate;
    }

    /**
     * 加入购物车
     *
     * @param pid
     * @param num
     * @param cartToken
     * @return
     */
    @Override
    public ResultMessage add(Long pid, Integer num, String cartToken) {
        List<CartItem> cartItems=null;
        //先判断redis里有没有这个购物车
        Object obj = redisTemplate.opsForValue().get(RedisConstant.CART_TOKEN + cartToken);
        if (obj == null) {
            //没有，则根据cartToken创建新的redis条目
            //先判断给的pid和num值是否合法
            if(pid>0&&num>0){
                //合法值
                cartItems=new ArrayList<>();
                CartItem cartItem=new CartItem();
                cartItem.setPid(pid);
                cartItem.setNum(num);
                cartItem.setUpdateTime(new Date());
                cartItems.add(cartItem);
                redisTemplate.opsForValue().set(RedisConstant.CART_TOKEN + cartToken,cartItems);
                return new ResultMessage(true,"success for new",cartItems);
            }else {
                //非法参数
                return new ResultMessage(false,"invalid params","参数不合法");
            }
        }else{
            //有，则进行获取并增删
            cartItems= (List<CartItem>) obj;
            //先判断给的pid和num值是否合法
            if(pid>0){
                //pid属于合法值
                //判断是否已经有相同商品
                boolean duplicate=false;
                for (CartItem item : cartItems) {
                    if (item.getPid().equals(pid)) {
                        duplicate = true;
                        break;
                    }
                }
                if(duplicate){
                    //已有相同商品
                    if(num>0){
                        //叠加
                        for (CartItem item : cartItems) {
                            if(item.getPid().equals(pid)){
                                item.setNum(item.getNum()+num);
                            }
                        }
                        //重新写回redis
                        redisTemplate.opsForValue().set(RedisConstant.CART_TOKEN + cartToken,cartItems);
                        return new ResultMessage(true,"success for old add",cartItems);
                    }else if(num.equals(-1)){
                        //对已有商品减一
                        Iterator<CartItem> iterator = cartItems.iterator();
                        while(iterator.hasNext()){
                            CartItem item = iterator.next();
                            if(item.getPid().equals(pid)){
                                //减一之前判断是否会归零
                                if(item.getNum()-1<=0){
                                    iterator.remove();
                                }else{
                                    item.setNum(item.getNum()-1);
                                    break;
                                }
                            }
                        }

                        //重新写回redis
                        //检测购物车内是否还有内容，没有则删除redis条目
                        if (cartItems == null||cartItems.size()==0) {
                            redisTemplate.delete(RedisConstant.CART_TOKEN + cartToken);
                            return new ResultMessage(false,"success for del in redis","redis购物车空了");
                        }else{
                            redisTemplate.opsForValue().set(RedisConstant.CART_TOKEN + cartToken,cartItems);
                            return new ResultMessage(true,"success for old -1",cartItems);
                        }
                    }else if(num.equals(-2)){
                        //对已有商品清零
                        Iterator<CartItem> iterator = cartItems.iterator();
                        while(iterator.hasNext()){
                            CartItem item = iterator.next();
                            if(item.getPid().equals(pid)){
                                //直接删除对应的购物车条目
                                iterator.remove();
                            }
                        }
                        //重新写回redis
                        //检测购物车内是否还有内容，没有则删除redis条目
                        if (cartItems == null||cartItems.size()==0) {
                            redisTemplate.delete(RedisConstant.CART_TOKEN + cartToken);
                            return new ResultMessage(false,"success for del in redis","redis购物车空了");
                        }else{
                            redisTemplate.opsForValue().set(RedisConstant.CART_TOKEN + cartToken,cartItems);
                            return new ResultMessage(true,"success for old -1",cartItems);
                        }
                    } else {
                        //非法参数
                        return new ResultMessage(false,"invalid params","参数不合法");
                    }
//                    //已有相同商品并处理完成，重新写入redis
//                    redisTemplate.opsForValue().set(RedisConstant.CART_TOKEN + cartToken,cartItems);
//                    return new ResultMessage(true,"success for old +1",cartItems);
                }else{
                    //没有相同商品，对list增添并写入redis
                    //判断给的num值是否合法
                    if(num>0){
                        //合法
                        CartItem cartItem=new CartItem();
                        cartItem.setPid(pid);
                        cartItem.setNum(num);
                        cartItem.setUpdateTime(new Date());
                        cartItems.add(cartItem);
                        redisTemplate.opsForValue().set(RedisConstant.CART_TOKEN + cartToken,cartItems);
                        return new ResultMessage(true,"success for old add",cartItems);
                    }else{
                        //非法
                        return new ResultMessage(false,"invalid params","参数不合法");
                    }

                }
            }else {
                return new ResultMessage(false,"invalid params","参数不合法");
            }
        }
    }

    /**
     * 展示购物车
     *
     * @param cartToken
     * @return
     */
    @Override
    public ResultMessage show(String cartToken) {
        //通过cartToken去redis读取购物车
        List<CartItem> cartItems=null;
        List<CartItemVO> cartItemVOList=new ArrayList<>();
        Object obj = redisTemplate.opsForValue().get(RedisConstant.CART_TOKEN + cartToken);
        try {
            cartItems= (List<CartItem>) obj;
            if (obj != null&&cartItems.size()>0) {
                //读取到了，则返回

                //从数据库或redis读取对应pid的商品数据并封装
                for (CartItem item : cartItems) {
                    //从数据库读取
                    Product product = productMapper.find(item.getPid());
                    //从redis读=====>还没写呢。你大爷的
                    //
                    //
                    //
                    cartItemVOList.add(new CartItemVO(product,item.getNum(),item.getUpdateTime()));
                }
                //对购物车的条目进行排序
                Comparator<CartItemVO> comparator=new Comparator<CartItemVO>() {
                    @Override
                    public int compare(CartItemVO o1, CartItemVO o2) {
                        return (int) (o2.getUpdateTime().getTime()-o1.getUpdateTime().getTime());
                    }
                };
                Collections.sort(cartItemVOList,comparator);
                return new ResultMessage(true,"读取到购物车",cartItemVOList);
            }else {
                //没读取到，则报错
                return new ResultMessage(false,"没找到对应购物车","没找到对应购物车");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return new ResultMessage(false,"没找到对应购物车",e.getMessage());
        }
    }

    /**
     * 合并购物车
     *
     * @param cartToken
     * @param loginToken
     * @return
     */
    @Override
    public ResultMessage merge(String cartToken, String loginToken) {
        //执行到这里是应该是既有cartToken，也有loginToken
        //并且controller已经检查过loginToken的合法性
        //检查cartToken的内容，确定作为匿名时的购物车有内容，再合并到登录的用户购物车下
        List<CartItem> cartTokenList= (List<CartItem>)redisTemplate.opsForValue().get(RedisConstant.CART_TOKEN + cartToken);
        List<CartItem> loginTokenList=(List<CartItem>)redisTemplate.opsForValue().get(RedisConstant.CART_TOKEN + loginToken);
        if (cartTokenList.size()==0||cartTokenList==null) {
            //检查到cartToken下购物车无数据,不合并，直接返回原内容

            //删除对应cartToken
            redisTemplate.delete(RedisConstant.CART_TOKEN + cartToken);

            return new ResultMessage(false,"failed","cartToken下购物车无数据");
        }else{
            //需要合并
//            ResultMessage loginTokenMessage = this.show(loginToken);
//            ResultMessage cartTokenMessage = this.show(cartToken);

//            //检查login_token对应有无购物车
//            if (loginTokenList.size()>0&&loginTokenList!=null) {
//
//            }else{
//                loginTokenList= null;
//            }

            //合并
            List<CartItem> tempList=null;
            //合并时，先检查是否有一方是空的
            if(loginTokenList==null||loginTokenList.size()==0||cartTokenList==null||cartTokenList.size()==0){
                //直接合并
                tempList=new ArrayList<>();
                tempList.addAll(cartTokenList);
            }else{
                //并不是有空的，则复杂合并
                //先将已登录用户的购物车存到map
                Map<Long,CartItem> newMap=new HashMap<>();
                for (CartItem cartItem : loginTokenList) {
                    newMap.put(cartItem.getPid(),cartItem);
                }
                //再遍历临时的购物车
                for (CartItem cartItem : cartTokenList) {
                    if (newMap.containsKey(cartItem.getPid())) {
                        //有重复的
                        CartItem temp=new CartItem();
                        temp.setUpdateTime(cartItem.getUpdateTime().getTime()>newMap.get(cartItem.getPid())
                                .getUpdateTime().getTime()?cartItem.getUpdateTime():
                                newMap.get(cartItem.getPid()).getUpdateTime());
                        temp.setNum(cartItem.getNum()+newMap.get(cartItem.getPid()).getNum());
                        //重新写入map
                        newMap.put(cartItem.getPid(),temp);
                    }else{
                        //不重复的，直接添加
                        newMap.put(cartItem.getPid(),cartItem);
                    }

                }
                //此时的map中不再有重复的
                tempList= new ArrayList(newMap.values());
                //redisTemplate.opsForValue().set(RedisConstant.CART_TOKEN + loginToken,tempList);
            }
            redisTemplate.opsForValue().set(RedisConstant.CART_TOKEN + loginToken,tempList);
            //将cartToken的值删除
            redisTemplate.delete(RedisConstant.CART_TOKEN + cartToken);
            //将loginToken的值返回
            ResultMessage message = new ResultMessage();
            message.setData(tempList);
            return message;
        }
    }

    /**
     * 消息队列合并购物车
     *
     * @param cart_token
     * @param login_token
     * @return
     */
    @Override
    public ResultMessage mergeByMQ(String cart_token, String login_token) {
        //先判断是否登录,以及是否同时拥有cart_token和login_token
        boolean cart_token_flag = StringUtils.isEmpty(cart_token);
        boolean login_token_flag = StringUtils.isEmpty(login_token);
        if(!login_token_flag){
            //已经登录
            //通过login_token获取user的对象
            LoginUser userByLoginToken = this.getUserByLoginToken(login_token);
            if (userByLoginToken == null) {
                //没有找对应login_token的user
                return new ResultMessage(false,"failed","login_token error");
            }else{
                //检查是否需要合并
                ResultMessage mergeAfterMessage = null;
                if (!cart_token_flag) {
                    //需要合并
                    mergeAfterMessage = this.merge(cart_token, userByLoginToken.getId().toString());

                    return mergeAfterMessage;
                } else {
                    //不需要合并，直接创建新的

                    return new ResultMessage(false,"failed","不需要合并");
                }
            }
        }else{
            //登录信息有误

            return new ResultMessage(false,"failed","没有登录信息，不能合并");
        }
    }

    /**
     * 通过loginToken获取登录用户对象
     *
     * @param loginToken
     * @return
     */
    @Override
    public LoginUser getUserByLoginToken(String loginToken) {
        //restTemplate开始
        String url="http://shop-user-service:8001/login/status.action";
        HttpHeaders headers=new HttpHeaders();
        List cookie=new ArrayList();
        cookie.add("login_token=" + loginToken);
        headers.put(HttpHeaders.COOKIE,cookie);
        HttpEntity httpEntity=new HttpEntity(headers);
        ResultMessage resultMessageForUser = restTemplate.postForObject(url,httpEntity, ResultMessage.class);
        log.error("getUserByLoginToken  获取到的数据===> "+resultMessageForUser.getData());
        //restTemplate结束
        //处理获取到的数据
        Map data = (Map)resultMessageForUser.getData();
        return BeanUtil.toBean(data, LoginUser.class);
    }
}
